<template>
    <div id="app">
        <div class="chat-service">
            <div class="box fl" :class="{show: !isShowUser}">
                <div class="title">
                    {{ curSite }}：客服{{ kfName }} 
                    <button @click="loginOut">退出</button>

                    <button v-show="!isShowUser" @click="isShowUser = true" class="fr">用户</button>

                    <button v-show="isShowUser" @click="isShowUser = false" class="hide">收起用户</button>
                </div>
                <div class="message-list" ref="wrapbox">
                    <div class="sys-msg" v-show="!isConnecting">未连接上服务器，正在尝试重新连接</div>
                    <div v-for="(item, idx) of messageList" :key="idx">
                        <!-- 系统消息 -->
                        <div class="sys-msg" v-if="item.data.type === 1" v-html="item.data.msg"></div>
                        <div class="message clearfix" v-if="(item.fd === curUser.fd || (item.userID >0 && item.userID == curUser.userID))">
                            <!-- 名字 + 时间 -->
                            <div class="user-id" :class="{'self': item.data.userName == kfName}">
                                <img v-if="item.data.userName != kfName" :src="curUser.headimg? curUser.headimg: `https://www.${curSite}.com/assets/images/headimg.png`" alt="">
                                <span v-if="item.data.userName != kfName">{{ curUser.username }} 
                                    <i style="font-size: 14px; color: #999; font-style: normal;">{{ curUser.userID > 0? '(id-'+curUser.userID+')': '' }}</i>：
                                </span>
                                <em>{{ item.data.time_show || item.data.time }}</em>
                            </div>
                            <!-- 文字消息 -->
                            <div class="msg" :class="{'self': item.data.userName == kfName}" v-if="item.data.msg" v-html="dealImg(item.data.msg)"></div>

                            <!-- 图片消息 -->
                            <div class="msg" :class="{'self': item.data.userName == kfName}" v-if="item.data.pic"><img class="img" :src="item.data.pic" @click="showBigImg(item.data.pic)"></div>
                        </div>
                    </div>
                </div>
                <div class="msg-send">
                    <form @submit.prevent="C2SMessage">
                        <textarea placeholder="输入消息开始聊天吧" @keypress.enter.prevent="C2SMessage" v-model="message" cols="30" rows="5"></textarea>
                        <button>发送</button>
                    </form>
                    <div class="emjoy">
                        <span class="emjoy-icon" @click="imgShow = !imgShow"><i></i></span>
                        <div class="emjoy-wrap" v-show="imgShow">
                            <ul>
                                <li v-for="(item, index) in imgsData" :key="index" @click="sendImg(item)"><img :src="item.src" :title="item.title"></li>
                            </ul>
                        </div>
                    </div>
                    <div class="pic">
                        <a>
                            <span>发图</span>
                            <input type="file" id="files" multiple @change="upImgs($event)" :accept="filetypes">
                        </a>
                    </div>
                </div>
                <div class="form-box" v-if="!hasUserName" @submit.prevent="loginIn">
                    <!-- <form @submit.prevent="setName" >
                        <input type="text" v-model="kfName" placeholder="请输入客服名称">
                        <button>确定</button>
                    </form> -->
                    <form>
                        <p>客服登录</p>
                        <fieldset>
                            站点：
                            <select v-model="loginData.site">
                                <option v-for="item in siteArr" :value="item">{{ item }}</option>
                            </select>
                        </fieldset>
                        <fieldset>
                            账号：
                            <input type="text" v-model.trim="loginData.name">
                        </fieldset>
                        <fieldset>
                            密码：
                            <input type="password" v-model.trim="loginData.passwd">
                        </fieldset>
                        <button>登录</button>
                    </form>

                </div>
                <div class="img-mask" v-show="showImgMask" @click="showImgMask=false">
                    <span>X</span>
                    <img :src="showImgSrc" @click.prevent.stop>
                </div>
            </div>
            <div class="users fr" v-show="isShowUser">
                <div class="user-name" 
                    v-for="(item, index) in userList" 
                    :class="{leave: (item.data.status === 'leave' && item.data.fd !== 0), active: (curUser.fd === item.data.fd || (curUser.userID > 0 && curUser.userID === item.data.userID))}" 
                    @click="checkToUser(item, index)">
                    <img v-if="item.data.fd !== 0" :src="item.data.headimg? item.data.headimg: `https://www.${curSite}.com/assets/images/headimg.png`" alt="">
                    <i> {{ item.data.username }} </i>
                    <!-- <em> {{ item.data.userID > 0? 'id:'+item.data.userID: '' }}</em> -->
                    <span v-if="unReadNum(item.data).length > 0">{{ unReadNum(item.data).length }}</span>
                    <span v-if="item.data.status === 'leave'" class="close" @click.prevent.stop="removeLeaveUser(item, index)">X</span>
                </div>
            </div>
        </div>
        <audio ref="audio">
            <source :src="curAudio">
        </audio>
    </div>
</template>
<script>
import { createSocket, destroySocket } from '@/socket'
import { IMGDAT } from '@/emjoy'

export default {
    name: 'app',
    data() {
        return {
            siteArr: [
                '52112',
                'macv',
                'macsc',
                'macxf',
                'single',
                'mac69',
                'mac89',
            ],
            tipvodio: [
                './call.mp3',
                './call2.mp3',
                './call3.mp3',
                './call4.mp3',
                './call4.mp3',
                './call4.mp3',
                './call4.mp3',
            ],
            messageList: [],
            kfName: '',
            kfID: '',
            message: '',
            hasUserName: false,
            imgsData: [],
            imgShow: false,
            filetypes: 'image/jpg,image/jpeg,image/png,image/gif',
            isLoading: false,
            picSrc: '',
            showImgSrc: '',
            showImgMask: false,
            msgTitle: document.title,
            msgTime: 0,
            msgTimer: null,
            userList: [],
            curUser: {},
            curSite: '',
            isConnecting: false,
            loginData: {
                name: '',
                passwd: '',
                site: ''
            },
            isShowUser: true,
            icoHref: '',
            // 心跳检测
            heartTimeout: 300 * 1000,
            heartTimer: null,
            heartServerTimer: null,
        }
    },


    computed: {
        curAudio() {
            return this.tipvodio[this.siteArr.indexOf(this.loginData.site)];
        }
    },


    created() {
        this.imgsData = IMGDAT.imgs;
        this.loginData.site = window.location.search.substr(1) || 'macv';

        // 修改站点名与ico图标
        this.icoHref = this.loginData.site + '.ico';

        let link = document.querySelector('link[rel*="icon"]');
        link.href = this.icoHref;
        document.getElementsByTagName("title")[0].innerText = this.loginData.site + '客服系统';

        this.testLogin();
    },

    mounted() {
        let _this = this;
        document.onvisibilitychange = function () {  
            if(!document.hidden) {
                _this.clearMsgTip();
            }
        };

        window.onbeforeunload = ()=> {
            this.closeSocket();
        };
    },

    beforeDestroy() {
        this.closeSocket();
    },

    watch: {
        messageList() {
            this.$nextTick(() => {
                this.$refs.wrapbox.scrollTop = this.$refs.wrapbox.scrollHeight;
            });
        }
    },

    methods: {
        // 重置心跳
        resetHeart() {
            this.heartTimer && clearTimeout(this.heartTimer);
            this.heartServerTimer && clearTimeout(this.heartServerTimer);
        },

        // 开始心跳检测
        startHeart() {
            this.resetHeart();

            this.heartTimer = setTimeout(()=> {
                // 发送心跳到后台
                this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                    msg: 'heartBeat',
                    site: this.loginData.site
                })

                this.heartServerTimer = setTimeout(()=> { 
                    // 服务器断连后 重新连接并重新检测
                    this.isConnecting = false;
                    // 关闭旧连接
                    this.closeSocket();
                    // 判断登录状态并重新连接
                    this.testLogin();
                }, 5000)

            }, this.heartTimeout)
        },

        // 判断登录状态
        testLogin() {
            this.$axios({
                method: 'get',
                url: `/api/get_login.php?site=${this.loginData.site}`,
            }).then(res=> {
                if(!res.data.is_login) {
                    this.hasUserName = false;
                } else {
                    this.hasUserName = true;
                    // 已经登录
                    this.curSite = res.data.admin_customer.site;
                    this.kfName = res.data.admin_customer.name;
                    this.kfID = res.data.admin_customer.id
                    this.setName();
                }
            }).catch(res=> {
                setTimeout(()=> {
                    this.testLogin();
                }, 5000);
            })
        },

        // 登录
        loginIn() {
            if(!this.loginData.name || !this.loginData.passwd || !this.loginData.site) {
                alert('输入不能为空');
            } else {
                let data = new FormData();
                data.append("name", this.loginData.name);
                data.append("passwd", this.loginData.passwd);
                data.append("site", this.loginData.site);

                this.$axios({
                    method: 'post',
                    url: '/api/login.php',
                    data,
                }).then(res=> {
                    if(res.data/1 === 1) {
                        this.testLogin();
                    } else {
                        alert('登录失败，请确认账号密码后再试！')
                    }
                })
            }
        },

        // 退出
        loginOut() {
            this.$axios({
                method: 'get',
                url: `/api/logout.php?site=${this.loginData.site}`,
            }).then(res=> {
                if(res.data) {
                    this.curSite = '';
                    this.kfName = '';
                    this.kfID = '';
                    this.userList = [];
                    this.hasUserName = false;

                    this.closeSocket();
                }
            })
        },

        unReadNum(item) {
            return this.messageList.filter(v=> {
                if (v.fd === item.fd || (item.userID > 0 && v.userID === item.userID)) {
                    return !v.isRead
                }
            })
        },

        checkToUser(item, index) {
            if(index > 1){
                this.userList.splice(1, 0, this.userList.splice(index, 1)[0]);
            }
            this.curUser = item.data;

            this.messageList.forEach(v=> {
                if (item.data.fd === v.fd || (v.userID > 0 && item.data.userID === v.userID)) {
                    v.isRead = true;
                }
            })

            this.$nextTick(() => {
                this.$refs.wrapbox.scrollTop = this.$refs.wrapbox.scrollHeight;
            });
        },

        // 移除离线用户
        removeLeaveUser(item, index) {
            this.userList.splice(index, 1);

            if(item.data.fd === this.curUser.fd) {
                this.curUser = this.userList[0].data;
            }
        },

        closeSocket() {
            if(this.$socket) {
                this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                    msg: '已离开',
                    accept_fd: 0,
                    site: this.curSite
                })

                this.$socket.removeListener(this.$socket.S2C_MESSAGE)
                destroySocket()

                // this.userList = [];
                // 关闭心跳检测
                this.resetHeart();
            } 
        },
        // 返回当前时间
        getCurTime() {
            let curDate = new Date();
            let Y = curDate.getFullYear(),
                M = this._checktime(curDate.getMonth() + 1),
                D = this._checktime(curDate.getDate()),
                h = this._checktime(curDate.getHours()),
                m = this._checktime(curDate.getMinutes()),
                s = this._checktime(curDate.getSeconds());


            return `${Y}/${M}/${D} ${h}:${m}:${s}`
        },

        // 发送表情
        sendImg(item) {
            this.imgShow = false;
            this.message += `:)${ item.title }:`;
        },

        // 设置昵称
        setName() {
            if(this.kfName == '') return;
            createSocket();
            this.$socket.addListener(this.$socket.S2C_MESSAGE, (...args) => {
                this.S2CMessage(...args)
            });
            this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                customer: 1,
                userID: this.kfID,
                username: this.kfName,
                site: this.curSite
            })

            // 心跳检测
            this.startHeart();
        },

        // 处理表情包
        dealImg: function(data) {
            return data.replace(/&lt;img src="/g, '<img src="')
                .replace(/\.gif"&gt;/g, '.gif">')
        },

        // 服务器返回消息
        S2CMessage(data) {
            // 服务器有返回，状态连接
            this.isConnecting = true;
            // 添加群发
            if(!this.userList[0] || this.userList[0].data.fd !== 0) {
                this.userList.unshift({
                    data: {
                        username: '群发',
                        fd: 0
                    }
                })
            }
            
            // 存在在线用户自动加入
            if(data.user_info) {
                this.curUser = this.userList[0].data;

                if(data.user_info.length) {
                    let newArr = [...data.user_info];

                    // 登录用户去重
                    for(var i=0; i<newArr.length; i++){
                        for(var j=i+1; j<newArr.length; j++){
                            if(newArr[i].data.userID > 0 && newArr[i].data.userID === newArr[j].data.userID){
                                newArr[i].data.newFd = newArr[i].data.newFd
                                    ? [...newArr[i].data.newFd, newArr[j].data.fd]
                                    : [newArr[i].data.fd, newArr[j].data.fd]
                                newArr.splice(j,1);
                                j--;
                            }
                        }
                    }

                    this.userList.push(...newArr);
                    // 所有用户添加在线状态
                    this.userList.forEach(v=> {
                        v.data.status = 'in';
                    });
                }
            } else {
                // 新加入用户
                if(data.username) {
                    if(!this.checkHasUser(data, 1) && !this.checkHasUser(data, 2)) {
                        data.status = 'in';
                        this.userList.push({data})
                    }
                } else {
                    // 用户离开
                    if(data.msg === '已离开') {
                        this.userList.forEach((v,i)=> {
                            if(v.data.userID === -1) {
                                // 未登录用户离开直接删除
                                if(v.data.fd === data.fd) {
                                    this.userList.splice(i, 1)
                                }
                            } else {
                                // 已登录用户离开状态修改离线
                                if(!v.data.newFd || v.data.newFd.length === 1) {
                                    if(v.data.fd === data.fd || (v.data.newFd && v.data.newFd.indexOf(data.fd) > -1)) {
                                        // this.userList.splice(i, 1)
                                        v.data.status = 'leave';
                                        v.data.newFd = [];
                                    }
                                    if(v.data.newFd && v.data.newFd.length) {
                                        v.data.newFd.splice(v.data.newFd.indexOf(data.fd), 1)
                                    }
                                } else {
                                    v.data.newFd.splice(v.data.newFd.indexOf(data.fd), 1)
                                }
                            }
                        })

                        // if (data.fd === this.curUser.fd) {
                        //     this.curUser = this.userList[0].data
                        // }
                    } else {
                        // 心跳检测判断
                        if (data.msg !== 'heartbeat') {
                            this.$refs.audio.play();
                            // 新消息
                            this.messageList.push({
                                fd: data.fd,
                                userID: data.userID || -1,
                                data,
                                isRead: (this.curUser.fd === data.fd || (this.curUser.userID > 0 && this.curUser.userID === data.userID)) ? true: false,
                            })

                            // 获取用户当前索引位置
                            let userIndex = 0;
                            this.userList.forEach((v, i)=> {
                                if(v.data.fd === data.fd || (data.userID > 0 && v.data.userID === data.userID)) {
                                    userIndex = i;
                                }
                            });
                            // 新消息位置升到2
                            if(userIndex!=2){
                                this.userList.splice(2, 0, this.userList.splice(userIndex, 1)[0]);
                            }

                            // 关闭title闪烁提示
                            if(document.hidden) {
                                this.msgTipsShow();
                            }
                        }
                    }
                }
            }

            // 开始检测
            this.startHeart();
        },

        // 判断用户存在
        checkHasUser(item, type) {
            let has = false;
            this.userList.forEach(v=> {
                if(type === 1) {
                    if(v.data.fd === item.fd) {
                        has = true;
                        v.data.status = 'in';
                    }
                } else {
                    if(item.userID > 0 && v.data.userID === item.userID) {
                        v.data.newFd = v.data.newFd
                        ? [...v.data.newFd, item.fd]
                        : [v.data.fd, item.fd];

                        v.data.status = 'in';
                        has = true;
                    }
                }
            })

            return has;
        },

        // 发送到服务器
        C2SMessage() {
            // 空消息无法发送
            if (!this.message && !this.picSrc) return;

            if(!this.isConnecting) {
                this.messageList.push({
                    fd: -1,
                    data: {
                        type: 1,
                        msg: '服务器未连接，请联系开发人员',
                        pic: '',
                        time: this.getCurTime(),
                    },
                    isRead: true
                })

                return;
            }

            if(this.curUser.status === 'leave') {
                alert('无法给离线用户发送消息');
                return;
            }

            if(!!this.curUser.newFd) {
                this.curUser.newFd.forEach(v=> {
                    this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                        msg: this._htmlfilter(this.message),
                        site: this.curSite,
                        pic: this.picSrc,
                        accept_fd: v
                    })
                })
            } else {
                let inUser = this.userList.filter(v=> {
                    return v.status === 'in';
                })
                if(this.curUser.fd === 0 && (this.userList.length === 1 || inUser.length === 1) ) {
                    alert('当前没有在线用户,无法群发');
                    return
                }
                this.$socket && this.$socket.C2SMessage(this.$socket.C2S_MESSAGE, {
                    msg: this._htmlfilter(this.message),
                    site: this.curSite,
                    pic: this.picSrc,
                    accept_fd: this.curUser.fd
                })
            }
            

            this.messageList.push({
                fd: this.curUser.fd,
                data: {
                    msg: this._htmlfilter(this.message),
                    userName: this.kfName,
                    pic: this.picSrc,
                    time: this.getCurTime(),
                },
                isRead: true
            })

            this.message = ''
            this.picSrc = ''
        },

        returnImg(str) {
            let src;
            this.imgsData.forEach(v=> {
                if(v.title == str) {
                    src = v.src
                }
            })
            return `<img src="${ src }">`;
        },

        _htmlfilter(str) {
            let _this = this;
            if(typeof str != 'string') {
                return str;
            }
            let imgreg = /:\)\S{2}:/g;
            let reg = /[<>]/gi;
            return str
            .replace(imgreg, function(data) {
                let newStr = _this.returnImg(data.match(/[^:)]{2}/)[0])
                return newStr
            }).replace(reg, function(match) {
                switch(match) {
                    case '<':
                        return '&lt;'
                    case '>':
                        return '&gt;'
                    default:
                        break;
                }
            })
        },
        _checktime(i) {
            if(i < 10) {  
                i = "0" + i;  
            }  
            else{ i = i;}  
            return i;  
        },
        upImgs: function(event) {
            var fil = event.target.files;
            for (var i = 0; i < fil.length; i++) {
                this._reads(fil[i]);
            }
        },
        _reads: function(fil) {
            if(fil.type.indexOf('image') == -1) {
                alert('仅能上传图片类型')
                return;
            }
            var reader = new FileReader(),
                _this = this;
            reader.readAsDataURL(fil);
            reader.onloadstart = function () {  
                _this.isLoading = true;
            }
            reader.onload = function(){
                _this.isLoading = false;
                var image = new Image();
                image.src = reader.result;
                if(fil.size >= 1024*1024*2 ) {
                    alert('图片过大！');
                    return;
                }
                image.onload=function(){
                    _this.picSrc = reader.result;
                    _this.C2SMessage();
                };
            };
        },
        showBigImg(src) {
            this.showImgMask = true;
            this.showImgSrc = src;
        },
        msgTipsShow() {
            let _this = this;
            let title = _this.msgTitle.replace("【　　　】", "").replace("【新消息】", "");
            _this.msgTimer = setTimeout(function () {  
                _this.msgTime++;  
                clearTimeout(_this.msgTimer);
                _this.msgTipsShow();
                if (_this.msgTime % 2 == 0) {  
                    document.title = "【新消息】" + title  
                } else {  
                    document.title = "【　　　】" + title  
                };  
            }, 500);  
        },
        clearMsgTip() {
            clearTimeout(this.msgTimer);  
            this.msgTime = 0;
            document.title = this.msgTitle;
        }
    }
}
</script>
<style scoped>
@import './app.css';
</style>